package com.qububu.play.common.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.annotation.Resource;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

import org.springframework.stereotype.Service;

import com.qububu.db.dao.TalkDao;
import com.qububu.play.common.dto.ActionTalkoverDto;
import com.qububu.play.common.service.TalkService;

@Service
public class TalkServiceImpl implements TalkService{

	@Resource
	private TalkDao talkDao;
	
	/**
	 * 缓存设计：
	 * (1)cache("type-actionId-save", List<ActionTalkoverDto>)为指定actionType需要存入数据库的新数据缓存信息, 
	 * (2)cache("type-actionId", List<ActionTalkoverDto>)为指定actionType从数据库取出的旧数据缓存信息,
	 * (3)聚餐、运动、pk菜、吐槽4部分，每一部分都包含(1)(2)两种类型的缓存
	 * (4)每次获取数据需要获取新旧两部分缓存中的数据
	 * (5)在取数据时指定缓存计时器被激活,每隔一定时间(通过获取encache配置中的过期时间配置来决定)将新数据区域的数据取出并批量存入数据库
	 * */ 
	// 设计思路,将缓存分为两个部分,一部分装新增加的数据,一部分装原来的数据, 当新增加的数据达到一定数量后(或者在销毁前)---改为考虑使用定时器实现批量添加进数据库, 然后将新数据缓存移到旧缓存中, 问题：需要监听缓存销毁并在销毁前得到其数据
	@Resource
	private Cache talkCache;
	
	private static long savePeriod = 100 * 1000;
	
	// 开始存入数据的定时任务
	private static boolean timerStarted = false;
	private Timer saveDataTimer = null;
	
	/*private TalkServiceImpl() {
		long compareTime = 1000;
		savePeriod = talkCache.getCacheConfiguration().getTimeToIdleSeconds() * 1000 - compareTime;
	}*/
	
	public boolean doSaveTalkMessage(ActionTalkoverDto talkOverInfo) {
		// 存入缓存
		String key = getSaveKey(talkOverInfo.getType().toIntValue(), talkOverInfo.getActionId());
		if (doSaveTalkMessageToCacheElement(key, talkOverInfo)) {
			startTimer(talkOverInfo.getType().toIntValue(), talkOverInfo.getActionId());
			
			return true;
		}
		
		return false;
	}
	
	public List<ActionTalkoverDto> getTalkAboutMessages(int actionType,
			String actionId, int searchLimitBegin, int searchLimitEnd) {
		List<ActionTalkoverDto> resultList = getTalkMessages(actionType, actionId);
		
		if (resultList.size() > searchLimitEnd) {
			resultList = resultList.subList(searchLimitBegin, searchLimitEnd);
		} else {
			resultList = resultList.subList(searchLimitBegin, resultList.size());
		}
		
		return resultList;
	}
	
	public List<ActionTalkoverDto> getTalkMessages(int actionType, String actionId) {

		String saveKey = getSaveKey(actionType, actionId);
		String dataKey = getDataKey(actionType, actionId);
		List<ActionTalkoverDto> saveList = (List<ActionTalkoverDto>) getElementFromCache(saveKey);
		List<ActionTalkoverDto> dataList = (List<ActionTalkoverDto>) getElementFromCache(dataKey);
		List<ActionTalkoverDto> resultList = null;
		if ((saveList == null || saveList.size() == 0) && (dataList == null || dataList.size() == 0)) {
			resultList = talkDao.getTalkMessages(actionType, actionId);
			doSaveElemToCache(dataKey, resultList);
		} else {
			resultList = new ArrayList<ActionTalkoverDto>();
			if (dataList != null && dataList.size() > 0) {
				resultList.addAll(dataList);
			}
			if (saveList != null && saveList.size() > 0) {
				resultList.addAll(0, saveList);
			}
		}
		
		return resultList;
	}
	
	/**
	 * 启动隔时启动的Timer
	 * */
	private void startTimer(int actionType, String actionId) {
		if (!timerStarted) {
			long compareTime = 3000;
			savePeriod = talkCache.getCacheConfiguration().getTimeToIdleSeconds() * 1000 - compareTime;
//			System.out.println("\n\n---------间隔时间为---->"+ savePeriod+"-----\n\n");
			// 启动timer
			saveDataTimer = new Timer();
			saveDataTimer.scheduleAtFixedRate(new SaveTalks(actionType, actionId), 
					savePeriod, savePeriod);
		}
	}
	
	/**
	 * 得到缓存中的从数据库取出的数据的key
	 * */
	private String getDataKey(int actionType, String actionId) {
		return actionType + "-" + actionId;
	}
	
	/**
	 * 得到需要存入数据库的缓存key
	 * */
	private String getSaveKey(int actionType, String actionId) {
		return actionType + "-" + actionId + "-save";
	}
	
	private boolean doSaveTalkMessageToCacheElement(String key, ActionTalkoverDto talkMessage) {
		List<ActionTalkoverDto> talkList = (List<ActionTalkoverDto>) getElementFromCache(key);
		if (talkList == null) {
			talkList = new ArrayList<ActionTalkoverDto>();
			doSaveElemToCache(key, talkList);
		}
		talkList.add(0, talkMessage);
//		System.out.println("\n\n--------调试--[talkCache]--[向缓存[元素]中[存入]一个元素]-------\n\n");
		return true;
	}
	
	private Object getElementFromCache(String key) {
		Element cacheElem = talkCache.get(key);

		if (cacheElem != null) {
//			System.out.println("\n\n--------调试--[talkCache]--[从缓存中[取出]一个元素]-------\n\n");
			return cacheElem.getObjectValue();
		}
		return null;
	}
	
	private void doSaveElemToCache(String key, Object elem) {
		Element element = talkCache.get(key);
		if (element == null) {
			talkCache.put(new Element(key, elem));
//			System.out.println("\n\n--------调试--[talkCache]--[从缓存中[存入]一个元素]-------\n\n");
		}
	}
	
	private boolean transferSaveCacheToDataCache(String key, List<ActionTalkoverDto> saveList) {
		List<ActionTalkoverDto> dataList = (List<ActionTalkoverDto>) getElementFromCache(key);
		if (dataList != null) {
//			dataList.addAll(saveList);
//			System.out.println("\n\n--------调试--[talkCache]--[从[新元素]缓存[转移]到旧元素缓存]-------\n\n");
			return dataList.addAll(0, saveList);
		}
		
		return false;
	}

	// 清除指定key的缓存数据
	private boolean removeElementFromCache(String key) {
		if (talkCache.get(key) != null) {
//			System.out.println("\n\n--------调试--[talkCache]--[从缓存中[移除]一个元素]-------\n\n");
			return talkCache.remove(key);	
		}
		return true;
	}

	// 注销定时更新器并未下次下次触发定时更新器做好准备
	private void disableTimer() {
		timerStarted = false;
		saveDataTimer.cancel();
		saveDataTimer = null;
	}
	
	private class SaveTalks extends TimerTask {

		private String saveKey;
		private String dataKey;
		private SaveTalks(int actionType, String actionId) {
			timerStarted = true;
			this.saveKey = getSaveKey(actionType, actionId);
			this.dataKey = getDataKey(actionType, actionId);
//			System.out.println("\n\n\n-----定时器创建-->saveKey->"+saveKey+"--dataKey-->"+dataKey+"---\n\n\n");
		}
		
		@Override
		public void run() {
			List<ActionTalkoverDto> talkOverList = (List<ActionTalkoverDto>) getElementFromCache(saveKey);
			if (talkOverList.size() > 0) {
				doSave(talkOverList);
			}
		}
		
		private void doSave(List<ActionTalkoverDto> talkOverList) {
			if (talkDao.saveTalkMessages(talkOverList)) {
				if (transferSaveCacheToDataCache(dataKey, talkOverList)) {
					removeElementFromCache(saveKey);
				} else {
					removeElementFromCache(saveKey);
					removeElementFromCache(dataKey);
				}
				disableTimer();
			}
		}
	}
	
}
